#pragma once 

#include <iostream>
#include <queue>
#include <pthread.h>
#include "Task.hpp"
#include "Log.hpp"

#define NUM 6 //默认创建六个线程

class ThreadPool
{
    private:
        std::queue<Task> task_queue;
        int num; //创建线程的数量
        bool stop; //判断该线程池是否处于运行状态
        pthread_mutex_t lock; //创建一把互斥锁
        pthread_cond_t cond; //创建条件变量
        static ThreadPool* single_instance;
        ThreadPool(int _num = NUM)
            :num(_num),stop(false)
        {
            //初始化
            pthread_mutex_init(&lock , nullptr);
            pthread_cond_init(&cond , nullptr);
        }

        ThreadPool(const ThreadPool&){}
    public:
        static ThreadPool* getinstance()
        {
            static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;       
            if (single_instance == nullptr)
            {
                pthread_mutex_lock(&mtx);
                if (single_instance == nullptr)
                {
                    single_instance = new ThreadPool();
                    single_instance->InitThreadPool();
                }
                pthread_mutex_unlock(&mtx);
            }
            
            return single_instance;
        }

        bool IsStop()
        {
            return stop;
        }
         
        bool TaskQueueIsEmpty()
        {
            return task_queue.size() == 0 ? true : false;
        }

        void Lock()
        {
            pthread_mutex_lock(&lock);
        }
    
        void Unlock()
        {
            pthread_mutex_unlock(&lock);
        }

        //线程等待
        void ThreadWait()
        {
          //此时将让该线程睡眠
            pthread_cond_wait(&cond , &lock);
        }

        //唤醒线程
        void ThreadWakeup()
        {
            pthread_cond_signal(&cond); //唤醒一个线程
        }

        //因为线程的处理函数只有一个参数，不能有this指针
        static void* ThreadRoutine(void* arg)
        {
            ThreadPool* tp = (ThreadPool*)arg;

            while (true)
            {
                Task t;
                tp->Lock(); //先加锁
                while (tp->TaskQueueIsEmpty())
                {
                    tp->ThreadWait();
                }
                tp->PopTask(t); //将任务拿出来
                tp->Unlock();
                t.ProcessOn(); //处理这个任务
            }
        }

        bool InitThreadPool()
        {
            for (int i = 0 ; i < num ; i ++)
            {
                pthread_t tid;
                //此时将this指针作为参数传递过去，用来在静态函数中调用变量
                if (pthread_create(&tid , nullptr , ThreadRoutine , this) != 0)
                { //此时表示当前创建线程失败了
                    LOG(FATAL , "create thread pool error!");
                    return false;
                }
            }
            LOG(INFO , "create thread pool success!");
            return true;
        }

        void PushTask(const Task& task) //插入任务对象
        {
            Lock();
            //先判断是否是满的
            task_queue.push(task);
            Unlock();
            ThreadWakeup(); //此时表示多出了一个位置给该线程，那么就可以唤醒一个线程
        }

        void PopTask(Task& task) //该task是输出型参数，为了拿出来数据
        {
            task = task_queue.front();
            task_queue.pop();
        }

        ~ThreadPool()
        {
            //释放
            pthread_mutex_destroy(&lock);
            pthread_cond_destroy(&cond);
        }
};

ThreadPool* ThreadPool::single_instance = nullptr;
